package com.harmonyos.cases.utils;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManager;
import com.intellij.openapi.extensions.PluginId;
import org.jsoup.internal.StringUtil;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class VersionControlUtil {

    private static Map<String, String> latestVersionInfo = new HashMap<>();

    private static Thread thread = null;

    private static double percent = 0;

    private static final IdeaPluginDescriptor pluginDescriptor = PluginManager.getPlugin(PluginId.getId("com.harmonyos.cases"));

    /**
     * 获取最新版本信息
     *
     * @return
     */
    public static Map<String, String> parseLatestVersion() {
        URL url = null;
        try {
            url = new URL("https://gitee.com/harmonyos-cases/cases/raw/master/plugin/version.json");
            try (InputStream in = url.openStream()) {
                // 获取最新版本号以及版本信息
                return (latestVersionInfo = parseVersion(in));
            }
        } catch (IOException | IllegalArgumentException e) {
            e.printStackTrace();
        }
        return latestVersionInfo;
    }

    /**
     * 获取当前版本号
     *
     * @return
     */
    public static String parseCurVersion() {
        return pluginDescriptor.getVersion().split("-")[0];
    }

    private static Map<String, String> parseVersion(InputStream inputStream) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        Map<String, String> result = new HashMap<>();
        JsonNode curRootNode = objectMapper.readTree(inputStream);
        if (curRootNode.isArray()) {
            JsonNode jsonNode = curRootNode.get(0);
            String version = jsonNode.get("version").asText();
            String packageUrl = jsonNode.get("packageUrl").asText();
            JsonNode info = jsonNode.get("info");
            String content = info.get("content").asText();
            if (StringUtil.isBlank(version) || StringUtil.isBlank(packageUrl) || StringUtil.isBlank(content)) {
                throw new IllegalArgumentException("version must not be empty or info must be array");
            }
            result.put("content", content);
            result.put("version", version);
            result.put("packageUrl", packageUrl);
        }
        return result;
    }

    // 下载最新版本的插件
    public static void downloadLatestVersion(String destDirectory, ProgressFunction<Integer> progressCallBack) {
        String packageUrl = latestVersionInfo.get("packageUrl");
        thread = new Thread(new Runnable() {
            @Override
            public void run() {
                downloadZipFile(packageUrl, destDirectory, progressCallBack);
            }
        });
        thread.start();
    }

    private static void downloadZipFile(String zipUrl, String destDirectory, ProgressFunction<Integer> progressCallBack) {
        HttpURLConnection connection = null;
        try {
            if (StringUtil.isBlank(zipUrl) || StringUtil.isBlank(destDirectory) || progressCallBack == null) {
                throw new IllegalArgumentException(
                        "IllegalArgumentException(zipUrl=" + zipUrl +
                                ", destDirectory=" + destDirectory +
                                ", progressCallBack=" + progressCallBack +
                                ")"
                );
            }
            URL url = new URL(zipUrl);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setRequestProperty("Accept-Encoding", "identity");
            // 设置连接超时时间
            connection.setConnectTimeout(15000);
            connection.setReadTimeout(60000);
            connection.connect();
            if (connection.getResponseCode() == 200) {
                InputStream inputStream = connection.getInputStream();
                ZipInputStream zipInputStream = new ZipInputStream(inputStream);
                unzip(zipInputStream, destDirectory, progressCallBack);
                progressCallBack.apply(100);
            }
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e.getMessage());
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
            progressCallBack.stop();
        }
    }

    // 解压压缩包
    private static void unzip(ZipInputStream zipInputStream, String destDirectory, ProgressFunction<Integer> progressCallBack) throws IOException, InterruptedException {
        File destDir = new File(destDirectory);
        if (!destDir.exists()) {
            destDir.mkdir();
        }
        ZipEntry entry;
        percent = 0;
        while ((entry = zipInputStream.getNextEntry()) != null) {
            if (entry.isDirectory()) {
                File dir = new File(destDirectory, entry.getName());
                if (!dir.exists()) {
                    dir.mkdir();
                }
            } else {
                File file = new File(destDirectory, entry.getName());
                if (!file.exists()) {
                    file.createNewFile();
                }
                copyInputStream(new BufferedInputStream(zipInputStream),
                        new BufferedOutputStream(new FileOutputStream(file)),
                        progressCallBack);
            }
            zipInputStream.closeEntry();
        }
        zipInputStream.close();
    }

    // 获取压缩包内文件内容
    private static void copyInputStream(BufferedInputStream is, BufferedOutputStream os, ProgressFunction<Integer> progressCallBack) throws IOException, InterruptedException {
        byte[] buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = is.read(buffer)) != -1 && !Thread.currentThread().isInterrupted()) {
            os.write(buffer, 0, bytesRead);
        }
        percent = 0.8 * percent + 20;
        progressCallBack.apply((int) percent);
        if (Thread.interrupted()) {
            throw new InterruptedIOException("cancel download...");
        }
        os.close();
    }

    public static Map<String, String> getLatestVersionInfo() {
        return latestVersionInfo;
    }

    public static Thread getThread() {
        return thread;
    }

    public static boolean needUpdate(String currentVersion, String lastVersion) {
        if (currentVersion == null || lastVersion == null) {
            return false;
        }
        String[] current = currentVersion.split("\\.");
        String[] last = lastVersion.split("\\.");
        if (current.length != 3 || last.length != 3) {
            return false;
        }
        if (Integer.parseInt(last[0]) > Integer.parseInt(current[0])) {
            return true;
        }
        if (Integer.parseInt(last[0]) < Integer.parseInt(current[0])) {
            return false;
        }
        if (Integer.parseInt(last[0]) == Integer.parseInt(current[0])) {
//            Integer.parseInt(las)
        }
        for (int i = 0; i < 3; i++) {
            if (Integer.parseInt(last[i]) > Integer.parseInt(current[i])) {
                return true;
            }
            if (Integer.parseInt(last[i]) < Integer.parseInt(current[i])) {
                return false;
            }
        }
        return false;
    }
}
